{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "unique-neutral",
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import os\n",
    "import PIL\n",
    "import tensorflow as tf\n",
    "\n",
    "from tensorflow import keras\n",
    "from tensorflow.keras import layers\n",
    "from tensorflow.keras.models import Sequential"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "biblical-tractor",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "你的数据集路径\n"
     ]
    }
   ],
   "source": [
    "#待训练的图片数据集目录\n",
    "import pathlib\n",
    "data_dir = pathlib.Path('你的数据集路径')\n",
    "print(data_dir)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "continuous-airline",
   "metadata": {},
   "outputs": [],
   "source": [
    "batch_size = 32\n",
    "img_height = 28\n",
    "img_width = 28"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "marked-apache",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 63479 files belonging to 14 classes.\n",
      "Using 50784 files for training.\n"
     ]
    }
   ],
   "source": [
    "train_ds = tf.keras.preprocessing.image_dataset_from_directory(\n",
    "  data_dir,\n",
    "  validation_split=0.2,\n",
    "  subset=\"training\",\n",
    "  seed=123,\n",
    "  image_size = (img_height, img_width),\n",
    "  batch_size = batch_size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "civil-consistency",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 63479 files belonging to 14 classes.\n",
      "Using 12695 files for validation.\n"
     ]
    }
   ],
   "source": [
    "val_ds = tf.keras.preprocessing.image_dataset_from_directory(\n",
    "  data_dir,\n",
    "  validation_split=0.2,\n",
    "  subset=\"validation\",\n",
    "  seed=123,\n",
    "  image_size=(img_height, img_width),\n",
    "  batch_size=batch_size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "patent-illness",
   "metadata": {},
   "outputs": [],
   "source": [
    "num_classes = 10\n",
    "\n",
    "model = Sequential([\n",
    "  layers.experimental.preprocessing.Rescaling(1./255, input_shape=(img_height, img_width, 3)),\n",
    "  layers.Conv2D(16, 3, padding='same', activation='relu'),\n",
    "  layers.MaxPooling2D(),\n",
    "  layers.Conv2D(32, 3, padding='same', activation='relu'),\n",
    "  layers.MaxPooling2D(),\n",
    "  layers.Conv2D(64, 3, padding='same', activation='relu'),\n",
    "  layers.MaxPooling2D(),\n",
    "  layers.Flatten(),\n",
    "  layers.Dense(128, activation='relu'),\n",
    "  layers.Dense(num_classes)\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "minute-float",
   "metadata": {},
   "outputs": [],
   "source": [
    "model.compile(optimizer='adam',\n",
    "              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n",
    "              metrics=['accuracy'])\n",
    "#model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "limiting-guidance",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/50\n",
      "1587/1587 [==============================] - 39s 24ms/step - loss: 0.5742 - accuracy: 0.8086 - val_loss: 0.0968 - val_accuracy: 0.9696\n",
      "Epoch 2/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0876 - accuracy: 0.9726 - val_loss: 0.0637 - val_accuracy: 0.9808\n",
      "Epoch 3/50\n",
      "1587/1587 [==============================] - 30s 19ms/step - loss: 0.0590 - accuracy: 0.9818 - val_loss: 0.0673 - val_accuracy: 0.9796\n",
      "Epoch 4/50\n",
      "1587/1587 [==============================] - 28s 18ms/step - loss: 0.0441 - accuracy: 0.9861 - val_loss: 0.0758 - val_accuracy: 0.9779\n",
      "Epoch 5/50\n",
      "1587/1587 [==============================] - 28s 18ms/step - loss: 0.0352 - accuracy: 0.9885 - val_loss: 0.0640 - val_accuracy: 0.9826\n",
      "Epoch 6/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0295 - accuracy: 0.9900 - val_loss: 0.0721 - val_accuracy: 0.9821\n",
      "Epoch 7/50\n",
      "1587/1587 [==============================] - 30s 19ms/step - loss: 0.0229 - accuracy: 0.9924 - val_loss: 0.0888 - val_accuracy: 0.9798\n",
      "Epoch 8/50\n",
      "1587/1587 [==============================] - 30s 19ms/step - loss: 0.0237 - accuracy: 0.9923 - val_loss: 0.0750 - val_accuracy: 0.9833\n",
      "Epoch 9/50\n",
      "1587/1587 [==============================] - 29s 19ms/step - loss: 0.0225 - accuracy: 0.9930 - val_loss: 0.0956 - val_accuracy: 0.9802\n",
      "Epoch 10/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0165 - accuracy: 0.9950 - val_loss: 0.0774 - val_accuracy: 0.9839\n",
      "Epoch 11/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0158 - accuracy: 0.9947 - val_loss: 0.0908 - val_accuracy: 0.9813\n",
      "Epoch 12/50\n",
      "1587/1587 [==============================] - 32s 20ms/step - loss: 0.0169 - accuracy: 0.9941 - val_loss: 0.0818 - val_accuracy: 0.9843\n",
      "Epoch 13/50\n",
      "1587/1587 [==============================] - 30s 19ms/step - loss: 0.0130 - accuracy: 0.9959 - val_loss: 0.0823 - val_accuracy: 0.9847\n",
      "Epoch 14/50\n",
      "1587/1587 [==============================] - 28s 18ms/step - loss: 0.0140 - accuracy: 0.9953 - val_loss: 0.0854 - val_accuracy: 0.9837\n",
      "Epoch 15/50\n",
      "1587/1587 [==============================] - 33s 21ms/step - loss: 0.0111 - accuracy: 0.9963 - val_loss: 0.0940 - val_accuracy: 0.9845\n",
      "Epoch 16/50\n",
      "1587/1587 [==============================] - 30s 19ms/step - loss: 0.0110 - accuracy: 0.9966 - val_loss: 0.1397 - val_accuracy: 0.9779\n",
      "Epoch 17/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0191 - accuracy: 0.9946 - val_loss: 0.0920 - val_accuracy: 0.9833\n",
      "Epoch 18/50\n",
      "1587/1587 [==============================] - 28s 18ms/step - loss: 0.0124 - accuracy: 0.9963 - val_loss: 0.0992 - val_accuracy: 0.9850\n",
      "Epoch 19/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0122 - accuracy: 0.9966 - val_loss: 0.1091 - val_accuracy: 0.9820\n",
      "Epoch 20/50\n",
      "1587/1587 [==============================] - 28s 18ms/step - loss: 0.0112 - accuracy: 0.9965 - val_loss: 0.1156 - val_accuracy: 0.9824\n",
      "Epoch 21/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0112 - accuracy: 0.9970 - val_loss: 0.1119 - val_accuracy: 0.9835\n",
      "Epoch 22/50\n",
      "1587/1587 [==============================] - 30s 19ms/step - loss: 0.0106 - accuracy: 0.9971 - val_loss: 0.1112 - val_accuracy: 0.9850\n",
      "Epoch 23/50\n",
      "1587/1587 [==============================] - 30s 19ms/step - loss: 0.0098 - accuracy: 0.9969 - val_loss: 0.1323 - val_accuracy: 0.9820\n",
      "Epoch 24/50\n",
      "1587/1587 [==============================] - 30s 19ms/step - loss: 0.0082 - accuracy: 0.9972 - val_loss: 0.1045 - val_accuracy: 0.9852\n",
      "Epoch 25/50\n",
      "1587/1587 [==============================] - 30s 19ms/step - loss: 0.0133 - accuracy: 0.9963 - val_loss: 0.0957 - val_accuracy: 0.9867\n",
      "Epoch 26/50\n",
      "1587/1587 [==============================] - 29s 19ms/step - loss: 0.0104 - accuracy: 0.9972 - val_loss: 0.1267 - val_accuracy: 0.9835\n",
      "Epoch 27/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0129 - accuracy: 0.9965 - val_loss: 0.1246 - val_accuracy: 0.9857\n",
      "Epoch 28/50\n",
      "1587/1587 [==============================] - 30s 19ms/step - loss: 0.0096 - accuracy: 0.9970 - val_loss: 0.1204 - val_accuracy: 0.9842\n",
      "Epoch 29/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0097 - accuracy: 0.9973 - val_loss: 0.1016 - val_accuracy: 0.9850\n",
      "Epoch 30/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0092 - accuracy: 0.9972 - val_loss: 0.1270 - val_accuracy: 0.9840\n",
      "Epoch 31/50\n",
      "1587/1587 [==============================] - 28s 18ms/step - loss: 0.0145 - accuracy: 0.9961 - val_loss: 0.1300 - val_accuracy: 0.9846\n",
      "Epoch 32/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0095 - accuracy: 0.9972 - val_loss: 0.1037 - val_accuracy: 0.9863\n",
      "Epoch 33/50\n",
      "1587/1587 [==============================] - 31s 19ms/step - loss: 0.0076 - accuracy: 0.9981 - val_loss: 0.1446 - val_accuracy: 0.9821\n",
      "Epoch 34/50\n",
      "1587/1587 [==============================] - 30s 19ms/step - loss: 0.0076 - accuracy: 0.9978 - val_loss: 0.1145 - val_accuracy: 0.9859\n",
      "Epoch 35/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0060 - accuracy: 0.9985 - val_loss: 0.1316 - val_accuracy: 0.9841\n",
      "Epoch 36/50\n",
      "1587/1587 [==============================] - 31s 19ms/step - loss: 0.0082 - accuracy: 0.9975 - val_loss: 0.1333 - val_accuracy: 0.9834\n",
      "Epoch 37/50\n",
      "1587/1587 [==============================] - 31s 20ms/step - loss: 0.0124 - accuracy: 0.9971 - val_loss: 0.1334 - val_accuracy: 0.9834\n",
      "Epoch 38/50\n",
      "1587/1587 [==============================] - 30s 19ms/step - loss: 0.0080 - accuracy: 0.9983 - val_loss: 0.1351 - val_accuracy: 0.9857\n",
      "Epoch 39/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0090 - accuracy: 0.9976 - val_loss: 0.1527 - val_accuracy: 0.9835\n",
      "Epoch 40/50\n",
      "1587/1587 [==============================] - 37s 23ms/step - loss: 0.0103 - accuracy: 0.9978 - val_loss: 0.1480 - val_accuracy: 0.9845\n",
      "Epoch 41/50\n",
      "1587/1587 [==============================] - 30s 19ms/step - loss: 0.0120 - accuracy: 0.9975 - val_loss: 0.1298 - val_accuracy: 0.9860\n",
      "Epoch 42/50\n",
      "1587/1587 [==============================] - 28s 17ms/step - loss: 0.0078 - accuracy: 0.9979 - val_loss: 0.1411 - val_accuracy: 0.9849\n",
      "Epoch 43/50\n",
      "1587/1587 [==============================] - 30s 19ms/step - loss: 0.0088 - accuracy: 0.9977 - val_loss: 0.1433 - val_accuracy: 0.9850\n",
      "Epoch 44/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0112 - accuracy: 0.9976 - val_loss: 0.1662 - val_accuracy: 0.9841\n",
      "Epoch 45/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0059 - accuracy: 0.9982 - val_loss: 0.1727 - val_accuracy: 0.9835\n",
      "Epoch 46/50\n",
      "1587/1587 [==============================] - 31s 19ms/step - loss: 0.0113 - accuracy: 0.9980 - val_loss: 0.1601 - val_accuracy: 0.9847\n",
      "Epoch 47/50\n",
      "1587/1587 [==============================] - 30s 19ms/step - loss: 0.0120 - accuracy: 0.9973 - val_loss: 0.1528 - val_accuracy: 0.9865\n",
      "Epoch 48/50\n",
      "1587/1587 [==============================] - 31s 19ms/step - loss: 0.0097 - accuracy: 0.9978 - val_loss: 0.1805 - val_accuracy: 0.9852\n",
      "Epoch 49/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0154 - accuracy: 0.9970 - val_loss: 0.1513 - val_accuracy: 0.9859\n",
      "Epoch 50/50\n",
      "1587/1587 [==============================] - 29s 18ms/step - loss: 0.0082 - accuracy: 0.9982 - val_loss: 0.1399 - val_accuracy: 0.9879\n"
     ]
    }
   ],
   "source": [
    "epochs=50\n",
    "history = model.fit(\n",
    "  train_ds,\n",
    "  validation_data=val_ds,\n",
    "  epochs=epochs\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "random-ordinary",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "数字识别结果： 4 概率： 100.00 %\n"
     ]
    }
   ],
   "source": [
    "\n",
    "#输入一张图片进行分类\n",
    "class_names = train_ds.class_names\n",
    "#sunflower_url = \"https://storage.googleapis.com/download.tensorflow.org/example_images/592px-Red_sunflower.jpg\"\n",
    "#sunflower_path = tf.keras.utils.get_file('Red_sunflower', origin=sunflower_url)\n",
    "\n",
    "img = keras.preprocessing.image.load_img(\n",
    "    '你的数据集路径/4/e180010b-6417-462e-bf07-b163ea592c2f.png', target_size=(img_height, img_width)\n",
    ")\n",
    "\n",
    "#图片转换成数组\n",
    "img_array = keras.preprocessing.image.img_to_array(img)\n",
    "img_array = tf.expand_dims(img_array, 0) # Create a batch\n",
    "\n",
    "predictions = model.predict(img_array)\n",
    "\n",
    "score = tf.nn.softmax(predictions[0])\n",
    "\n",
    "print(\n",
    "    \"数字识别结果： {} 概率： {:.2f} %\"\n",
    "    .format(class_names[np.argmax(score)], 100 * np.max(score))\n",
    ")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "radio-renewal",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:tensorflow:Assets written to: in_circle_nums/assets\n"
     ]
    }
   ],
   "source": [
    "model.save(\"in_circle_nums.h5\")\n",
    "model.save(\"in_circle_nums\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "balanced-colorado",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "solid-premises",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Convert the model\n",
    "converter = tf.lite.TFLiteConverter.from_saved_model(\"in_circle_nums\") # path to the SavedModel directory\n",
    "tflite_model = converter.convert()\n",
    "\n",
    "# Save the model.\n",
    "with open('in_circle_nums.tflite', 'wb') as f:\n",
    "  f.write(tflite_model)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "exotic-sellers",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "compound-setting",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
